﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Management;
using System.Text;
using System.Timers;
using System.Windows.Forms;
using JewelCaseWriter;
using MusicRipperDataAccess;
using log4net;

namespace UWSP_Music_Ripper
{
   public partial class Form1 : Form
   {
		#region Fields (9) 

      ILog mlog;
      Album myAlbum;
      AlbumHandler myAlbumHandler;
      CD_Reader.CD_Reader myCD;
      System.Timers.Timer myTimer;
      bool PrintLater;
      WqlEventQuery q;
      ManagementScope scope;
      ManagementEventWatcher w = null;

		#endregion Fields 

		#region Constructors (1) 

      public Form1()
      {
         InitializeComponent();
         log4net.Config.XmlConfigurator.Configure();
         mlog = LogManager.GetLogger(typeof(Form1));
         mlog.Debug("inside start up making a new album handler");
         this.myAlbumHandler = new AlbumHandler();
         mlog.Debug("now set up the timer");
         SetUpTimer();
         mlog.Debug("list out the drives");
         ListCdDrives();
         if (lstDrives.Items.Count > 0)
         {
            string s = lstDrives.Items[0].ToString().Substring(0, 1);
            myCD = new CD_Reader.CD_Reader(s);
         }
         this.lblSource.Text = ConfigurationManager.AppSettings["source"];
         this.lblDestination.Text = ConfigurationManager.AppSettings["destination"];
         this.PrintLater = System.Convert.ToBoolean ( ConfigurationManager.AppSettings["PrintLater"]);
         this.mnuPrintLater.Checked = this.PrintLater;
         mlog.Debug("Start monitoring the cd drive for new cds to burn");
         StartMonitoringCD();

      }

		#endregion Constructors 

		#region Delegates and Events (2) 

		// Delegates (2) 

      delegate void GetCdInfoCallBack();
      delegate void UpdateRipStatusCallBack(string inValue);

		#endregion Delegates and Events 

		#region Methods (23) 

		// Protected Methods (1) 

      /// <summary>
      /// Clean up any resources being used.
      /// </summary>
      /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
      protected override void Dispose(bool disposing)
      {
         w.Dispose();

         if (disposing && (components != null))
         {
            components.Dispose();
         }
         base.Dispose(disposing);
      }
		// Private Methods (22) 

      private void btnDrives_Click(object sender, EventArgs e)
      {
         System.IO.DriveInfo[] drives = System.IO.DriveInfo.GetDrives();
         List<string> myDrives = new List<string>();
         foreach (System.IO.DriveInfo drive in drives)
         {
            myDrives.Add(drive.Name + "  |  " + drive.DriveType.ToString());
         }
         this.lstTracks.DataSource = myDrives;
      }

      private void btnListTracks_Click(object sender, System.EventArgs e)
      {
         SetInfoFromCD();
      }

      private void btnPrint_Click(object sender, EventArgs e)
      {
         this.PrintJewelCase();
      }

      private void button1_Click(object sender, EventArgs e)
      {
         List<string> titles = myAlbumHandler.GetAlbumTitles ();
         StringBuilder sb = new StringBuilder ();
         foreach (string title in titles)
         {
            sb.Append (title + System.Environment.NewLine);
         }

         MessageBox.Show (sb.ToString ());

         //List<string> attributes = myCD.ListAllAttributes();

      }

      private void chooseSourceDirToolStripMenuItem_Click(object sender, EventArgs e)
      {
         FolderBrowserDialog fbd = new FolderBrowserDialog();
         if (fbd.ShowDialog() == DialogResult.OK)
         {
            this.lblSource.Text = fbd.SelectedPath;
            Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            config.AppSettings.Settings["source"].Value = fbd.SelectedPath;
            config.Save(ConfigurationSaveMode.Modified);
         }
      }

      private void destinationDirectoryToolStripMenuItem_Click(object sender, EventArgs e)
      {
         FolderBrowserDialog fbd = new FolderBrowserDialog();
         if (fbd.ShowDialog() == DialogResult.OK)
         {
            this.lblDestination.Text = fbd.SelectedPath;
         }
      }

      private List<string> GetTracksToRip()
      {
         mlog.Debug("inside get tracks to rip ");
         List<string> TracksToRip = new List<string>();
         foreach (object i in lstTracks.CheckedItems)
         {
            TracksToRip.Add(i.ToString());
            mlog.Debug("adding " + i.ToString());
         }
         return TracksToRip;
      }

      private void ListCdDrives()
      {

         System.IO.DriveInfo[] drives = System.IO.DriveInfo.GetDrives();
         List<string> myDrives = new List<string>();
         foreach (System.IO.DriveInfo drive in drives)
         {
            if (drive.DriveType == System.IO.DriveType.CDRom)
               myDrives.Add(drive.Name);
         }
         lstDrives.DataSource = myDrives;
      }

      private void lnkAll_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
      {
         for (int i = 0; i < lstTracks.Items.Count; i++)
         {
            this.lstTracks.SetItemChecked(i, true);
         }
      }

      private void lstDrives_SelectedIndexChanged(object sender, EventArgs e)
      {
         string s = lstDrives.SelectedItem.ToString().Substring(0, 1);
         myCD = new CD_Reader.CD_Reader(s);
      }

      private void mnuPrintLater_Click(object sender, EventArgs e)
      {
          this.PrintLater = !this.PrintLater;
          this.mnuPrintLater.Checked = this.PrintLater;
          Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
          config.AppSettings.Settings["PrintLater"].Value = this.PrintLater.ToString(); 
          config.Save(ConfigurationSaveMode.Modified);  
      }

      private void myTimer_Elapsed(object source, ElapsedEventArgs e)
      {
         mlog.Debug("check if the cd is done ripping or not.");
         UpdateRipStatus(myCD.GetRipProgress());
         string s = myCD.GetRipState();
         switch (s)
         {
            case "Done":
               myTimer.Stop();
               mlog.Debug("ok all done ripping the cd time stopped the timer and now move the files.");
               FileHelper fh = new FileHelper();
               if (fh.MoveFiles (this.lblSource.Text, this.lblDestination.Text, this.myAlbum))
               {
                  if (!this.PrintLater)
                  {
                     JewelCaseHelper.WriteTheCase (this.myAlbum);
                  }
                  mlog.Debug ("now add to the album collection and write it out to a file");
                  this.myAlbumHandler.AddToAlbums (this.myAlbum);
                  this.myAlbumHandler.WriteToFile ();
                  mlog.Debug ("now get rid of the album ");
                  myAlbum.Dispose ();
                  this.lblArtist.Text = String.Empty;
                  this.lblCD_Title.Text = String.Empty;
                  this.lstTracks.DataSource = null;
                  this.myCD.EjectCD ();
                
               }
               else
               {
                  mlog.Debug ("Failed to move the file, so send up the error message " + fh.ErrMessage);
                  MessageBox.Show (fh.ErrMessage);
                  fh.ErrMessage = string.Empty;
                  myAlbum.MyTracks.Clear ();
               }
                 
               break;
         }
      }

      private void PrintJewelCase()
      {
         JewelCaseHelper jch = new JewelCaseHelper();

         //jch.WriteTheCase(myData);

      }

   
      private void printOutNewJewelCaseToolStripMenuItem1_Click (object sender, EventArgs e)
      {
         frmPrintJewelCase fjc = new frmPrintJewelCase (this.myAlbumHandler);
         fjc.Show ();
      }

      private bool ReadyToRip()
      {
         bool ready = false;
         if (this.lblSource.Text.Equals("Source Directory", StringComparison.CurrentCultureIgnoreCase))
         {
            MessageBox.Show("You need to set the source directory to the same directory you windows Media Player rips to.");
         }
         else if (!FileHelper.DoesDirectoryExist (lblSource.Text))
         {
            MessageBox.Show ("The source directory does not exist.");
         }
         else if (this.lblDestination.Text.Equals ("Destination Directory", StringComparison.CurrentCultureIgnoreCase))
         {
            MessageBox.Show ("You need to set the destination directory to where you want the new files to be copied.");
         }
         else if (!FileHelper.DoesDirectoryExist (lblDestination.Text))
         {
            MessageBox.Show ("The destination directory does not exist.");
         }

         else if (!myCD.isCD_Ready ())
         {
            MessageBox.Show ("There is not a cd loaded yet");
         }
         else if (lstTracks.CheckedItems.Count == 0)
         {
            MessageBox.Show ("Pleae select some tracks to rip and rename");
         }
         else
         {
            ready = true;
         }
         return ready;
      }

      private void RipTracks(object sender, EventArgs e)
      {
         mlog.Debug("ok someone clicked the rip tracks button ");
         if (ReadyToRip())
         {
            mlog.Debug("ok we are going to get the tracks to rip ");
            List<string> TracksToRip = this.GetTracksToRip();
            mlog.Debug("we have " + TracksToRip.Count.ToString() + " tracks");
            mlog.Debug("tell the cd what tracks to rip");
            this.myCD.SetTracksToRip(TracksToRip);
            mlog.Debug("tell the album which tracks to rip");
            this.myAlbum.SetTracks(TracksToRip);
            mlog.Debug("tell the cd to rip the tracks");
            this.myCD.RipAllTracks();
            mlog.Debug("start the timer to see when the cd is done ripping the tracks");
            myTimer.Start();
         }
      }

      private void SetInfoFromCD()
      {
         mlog.Debug("inside SetInfoFromCD checking if invoke required.");
         if (this.lstTracks.InvokeRequired)
         {
            mlog.Debug("it was so call again.");
            GetCdInfoCallBack del = new GetCdInfoCallBack(SetInfoFromCD);
            this.Invoke(del, new object[0]);
         }
         else
         {
            mlog.Debug("it wasn't so fill out the display data.");
            string title = myCD.GetCD_Title();
            string artist = myCD.GetArtist();
            myAlbum = new Album(title, artist);
            this.lblCD_Title.Text = title;
            this.lblArtist.Text = artist;
            if (!myAlbumHandler.DoesThisAlbumExist(myAlbum))
            {
               this.lstTracks.DataSource = myCD.GetTracks();
               
            }
            else
            {
               mlog.Debug("that album was ripped already.");
               MessageBox.Show(title + " by " + artist + " already exists in the collection. Here are the tracks that have not been burned yet.");
               myAlbum = myAlbumHandler.GetAlbum (myAlbum.Artist, myAlbum.Title);
               this.lstTracks.DataSource = myCD.GetUnburnedTracks (myAlbum.TracksRippedAlready());
            }
         }
      }

      private void SetUpTimer()
      {
         myTimer = new System.Timers.Timer();
         myTimer.Elapsed += new ElapsedEventHandler(myTimer_Elapsed);
         myTimer.Interval = 2000;
         myTimer.SynchronizingObject = this;
      }

      private void StartMonitoringCD()
      {
         scope = new ManagementScope("root\\CIMV2");
         scope.Options.EnablePrivileges = true;

         q = new WqlEventQuery();
         q.EventClassName = "__InstanceModificationEvent";
         q.WithinInterval = new TimeSpan(0, 0, 1);
         // DriveType - 5: CDROM
         q.Condition = @"TargetInstance ISA 'Win32_LogicalDisk' and TargetInstance.DriveType = 5";
         w = new ManagementEventWatcher(scope, q);
         // register async. event handler
         w.EventArrived += new EventArrivedEventHandler(w_EventArrived);
         w.Start();
      }

      private void UpdateRipStatus(string inStatus)
      {
         if (this.lblRipStatus.InvokeRequired)
         {
            UpdateRipStatusCallBack del = new UpdateRipStatusCallBack(UpdateRipStatus);
            this.Invoke(del, new object[1] { inStatus });
         }
         else
         {
            this.lblRipStatus.Text = inStatus + "% done ripping this cd";
         }
      }

      private void w_EventArrived(object sender, EventArrivedEventArgs e)
      {

         //Get the Event object and display it
         PropertyData pd;
         if ((pd = e.NewEvent.Properties["TargetInstance"]) != null)
         {

            ManagementBaseObject mbo = pd.Value as ManagementBaseObject;
            // if CD removed VolumeName == null
            if (mbo.Properties["VolumeName"].Value != null)
            {

               this.SetInfoFromCD();
            }

         }
      }

		#endregion Methods 
   }
}
